package com.xinqi.modules.stats.score.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xinqi.common.base.response.R;
import com.xinqi.common.core.enums.ClassRoleEnum;
import com.xinqi.common.satoken.utils.LoginHelper;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.mybatis.data.service.impl.BaseServiceImpl;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.modules.course.clazz.client.ClassClient;
import com.xinqi.modules.course.clazz.client.ClassStudentClient;
import com.xinqi.modules.course.clazz.dto.req.ClassStudentQueryDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassResultDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassStudentResultDTO;
import com.xinqi.modules.course.course.client.RemoteCourseClient;
import com.xinqi.modules.course.course.dto.rsp.CourseResultDTO;
import com.xinqi.modules.stats.score.convert.CourseTotalScoreOfflineConvert;
import com.xinqi.modules.stats.score.domain.CourseTotalScoreOfflineEntity;
import com.xinqi.modules.stats.score.domain.CourseTotalScoreOfflineStudentEntity;
import com.xinqi.modules.stats.score.dto.req.*;
import com.xinqi.modules.stats.score.dto.rsp.*;
import com.xinqi.modules.stats.score.mapper.CourseTotalScoreOfflineMapper;
import com.xinqi.modules.stats.score.service.CourseTotalScoreOfflineConfigService;
import com.xinqi.modules.stats.score.service.CourseTotalScoreOfflineService;
import com.xinqi.modules.stats.score.service.CourseTotalScoreOfflineStudentService;
import com.xinqi.modules.stats.utils.ExcelUtil;
import com.xinqi.modules.stats.utils.MathUtils;
import lombok.RequiredArgsConstructor;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 线下成绩主表服务层实现
 *
 * @author: system
 * @date: 2023/03/26
 */
@Service
@RequiredArgsConstructor
public class CourseTotalScoreOfflineServiceImpl extends BaseServiceImpl<CourseTotalScoreOfflineMapper, CourseTotalScoreOfflineEntity> implements CourseTotalScoreOfflineService {

    private final CourseTotalScoreOfflineConvert courseTotalScoreOfflineConvert;

    private final CourseTotalScoreOfflineStudentService courseTotalScoreOfflineStudentService;

    private final CourseTotalScoreOfflineMapper courseTotalScoreOfflineMapper;

    private final CourseTotalScoreOfflineConfigService courseTotalScoreOfflineConfigService;

    private final ClassStudentClient classStudentClient;

    private final ClassClient classClient;

    private final RemoteCourseClient remoteCourseClient;

    @Override
    public boolean create(CourseTotalScoreOfflineCreateDTO create) {
        CourseTotalScoreOfflineEntity entity = courseTotalScoreOfflineConvert.create(create);
        // 同步线下成绩学生信息
        boolean flag = this.save(entity);
        this.syncStudentOffline(create.getClassId(), entity.getId());
        return flag;
    }

    private void syncStudentOffline(Long classId, Long offlineId) {
        List<ClassStudentResultDTO> studentList = R.as(classStudentClient.findClassMasterStudentByClassId(classId));
        // 校验学生数据
        studentList = studentList.stream().filter(v -> Objects.equals(ClassRoleEnum.STUDENT.getCode(), v.getClassRole())
                || Objects.equals(ClassRoleEnum.REPRESENTATIVE.getCode(), v.getClassRole())).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(studentList)) {
            List<CourseTotalScoreOfflineStudentEntity> entities = studentList.stream().map(v -> {
                CourseTotalScoreOfflineStudentEntity entity = new CourseTotalScoreOfflineStudentEntity();
                entity.setStudentId(v.getStudentId());
                entity.setScore(new BigDecimal(0));
                entity.setOfflineScoreId(offlineId);
                return entity;
            }).collect(Collectors.toList());
            courseTotalScoreOfflineStudentService.saveBatch(entities);
        }

    }

    @Override
    public boolean updateById(CourseTotalScoreOfflineUpdateDTO update) {
        CourseTotalScoreOfflineEntity entity = courseTotalScoreOfflineConvert.update(update);
        return this.updateById(entity);
    }

    @Override
    public List<CourseTotalScoreOfflineResultDTO> select(CourseTotalScoreOfflineQueryDTO query) {
        LambdaQueryWrapper<CourseTotalScoreOfflineEntity> wrapper = Queries.lambda();
        wrapper.eq(CourseTotalScoreOfflineEntity::getClassId, query.getClassId());
        // 获取查询者身份
        ClassStudentResultDTO student = classStudentClient.findByStudentId(query.getClassId(), LoginHelper.getUserId()).getData();
        List<CourseTotalScoreOfflineResultDTO> list = new ArrayList<>();
        if (Objects.equals(ClassRoleEnum.TEACHER.getCode(), student.getClassRole()) || Objects.equals(ClassRoleEnum.ASSISTANT.getCode(), student.getClassRole())) {
            list = this.baseMapper.selectDtoList(wrapper, courseTotalScoreOfflineConvert::convert);
        } else {
            list = courseTotalScoreOfflineMapper.getStudentTotalScoreOffline(query.getClassId(), student.getStudentId());
        }
        list.forEach(item -> {
            item.setIsUserLevelShow(item.getIsUseGradeShow());
            // 获取计算后的信息
            CourseTotalScoreOfflineResultDTO offline = this.baseMapper.allCourseTotalScoreOffline(item.getId());
            if (Objects.isNull(offline)) {
                return;
            }
            item.setFullScore(MathUtils.stripTrailingZeros(offline.getFullScore(), 1));
            item.setMaxScore(MathUtils.stripTrailingZeros(offline.getMaxScore(), 1));
            item.setAvgScore(MathUtils.stripTrailingZeros(offline.getAvgScore(), 1));
            item.setMinScore(MathUtils.stripTrailingZeros(offline.getMinScore(), 1));

            // 获取等级分制
            CourseTotalScoreOfflineConfigQueryDTO queryDTO = new CourseTotalScoreOfflineConfigQueryDTO();
            queryDTO.setOfflineScoreId(item.getId());
            List<CourseTotalScoreOfflineConfigResultDTO> configList = courseTotalScoreOfflineConfigService.findCourseTotalScoreOfflineConfig(queryDTO);
            item.setConfigList(configList);

            item.setFullGrade(checkTypeGrade(configList, item.getFullScore(), item.getFullScore()));
            item.setAvgGrade(checkTypeGrade(configList, item.getFullScore(), item.getAvgScore()));
            item.setMaxGrade(checkTypeGrade(configList, item.getFullScore(), item.getMaxScore()));
            item.setMinGrade(checkTypeGrade(configList, item.getFullScore(), item.getMinScore()));
        });
        return list;
    }

    @Override
    @DS("slaver")
    public PageInfo<CourseTotalScoreOfflineResultDTO> selectPage(CourseTotalScoreOfflineQueryDTO query) {
        LambdaQueryWrapper<CourseTotalScoreOfflineEntity> wrapper = Queries.lambda();
        wrapper.eq(CourseTotalScoreOfflineEntity::getClassId, query.getClassId());
        // 获取查询者身份
        ClassStudentResultDTO mainStudent = R.as(classStudentClient.findVirtualClassStudentByClassIdAndUserId(query.getClassId(), LoginHelper.getUserId()));
        if (Objects.isNull(mainStudent)) {
            return Pages.convert(courseTotalScoreOfflineMapper.getTotalScoreOfflinePage(Pages.page(query), query.getClassId(), query.getKeyWords()));
        } else {
            return Pages.convert(courseTotalScoreOfflineMapper.getStudentTotalScoreOfflinePage(Pages.page(query), query.getClassId(), mainStudent.getStudentId(), query.getKeyWords()));
        }
    }

    @Override
    public List<CourseTotalScoreOfflineResultDTO> studentSelect(CourseTotalScoreOfflineQueryDTO query) {
        Long studentId = LoginHelper.getUserId();
        List<CourseTotalScoreOfflineResultDTO> list = courseTotalScoreOfflineMapper.getStudentTotalScoreOffline(query.getClassId(), studentId);
        list.forEach(item -> {
            if (!item.getIsShowStudent().equals(0)) {
                // 获取计算后的信息
                CourseTotalScoreOfflineResultDTO offline = this.baseMapper.allCourseTotalScoreOffline(item.getId());
                item.setFullScore(MathUtils.stripTrailingZeros(offline.getFullScore(), 1));
                item.setMaxScore(MathUtils.stripTrailingZeros(offline.getMaxScore(), 1));
                item.setMinScore(MathUtils.stripTrailingZeros(offline.getMinScore(), 1));
                item.setAvgScore(MathUtils.stripTrailingZeros(offline.getAvgScore(), 1));
                item.setIsUserLevelShow(item.getIsUseGradeShow());

                // 获取等级分制
                CourseTotalScoreOfflineConfigQueryDTO queryDTO = new CourseTotalScoreOfflineConfigQueryDTO();
                queryDTO.setOfflineScoreId(item.getId());
                List<CourseTotalScoreOfflineConfigResultDTO> configList = courseTotalScoreOfflineConfigService.findCourseTotalScoreOfflineConfig(queryDTO);
                item.setConfigList(configList);

                //设置学生列表汇总等级分支
                item.setFullGrade(checkTypeGrade(configList, item.getFullScore(), item.getFullScore()));
                item.setAvgGrade(checkTypeGrade(configList, item.getFullScore(), item.getAvgScore()));
                item.setMaxGrade(checkTypeGrade(configList, item.getFullScore(), item.getMaxScore()));
                item.setMinGrade(checkTypeGrade(configList, item.getFullScore(), item.getMinScore()));

                // 获取学生成绩
                CourseTotalScoreOfflineStudentQueryDTO studentQueryDTO = new CourseTotalScoreOfflineStudentQueryDTO();
                studentQueryDTO.setOfflineScoreId(item.getId());
                studentQueryDTO.setStudentId(studentId);
                List<CourseTotalScoreOfflineStudentResultDTO> studentResultDTOS = courseTotalScoreOfflineStudentService.studentOfflineScoreList(studentQueryDTO);
                if (studentResultDTOS.size() > 0) {
                    item.setStudentScore(MathUtils.stripTrailingZeros(studentResultDTOS.get(0).getScore(), 1));
                    item.setGrade(checkTypeGrade(configList, item.getFullScore(), item.getStudentScore()));
                    item.setIsUserLevelShow(item.getIsUseGradeShow());
                }
            }
        });
        return list;
    }

    @Override
    public boolean deleteById(CourseTotalScoreOfflineDeleteDTO delete) {
        return this.deleteById(delete.getId());
    }

    @Override
    public List<CourseTotalScoreOfflineStudentResultDTO> selectStudentScore(CourseTotalScoreOfflineStudentQueryDTO query) {
        // 获取计算后的信息
        CourseTotalScoreOfflineResultDTO offline = this.baseMapper.allCourseTotalScoreOffline(query.getOfflineScoreId());
        // 获取等级分制
        CourseTotalScoreOfflineConfigQueryDTO queryDTO = new CourseTotalScoreOfflineConfigQueryDTO();
        queryDTO.setOfflineScoreId(query.getOfflineScoreId());
        List<CourseTotalScoreOfflineConfigResultDTO> configList = courseTotalScoreOfflineConfigService.findCourseTotalScoreOfflineConfig(queryDTO);

        List<CourseTotalScoreOfflineStudentResultDTO> list = this.courseTotalScoreOfflineStudentService.studentOfflineScoreList(query);
        list.forEach(item -> {
            item.setScore(MathUtils.stripTrailingZeros(item.getScore(), 1));
            item.setGrade(checkTypeGrade(configList, offline.getFullScore(), item.getScore()));
            item.setIsUserLevelShow(offline.getIsUseGradeShow());
            item.setIsUseGradeShow(offline.getIsUseGradeShow());
        });
        return list;
    }

    @Override
    public boolean updateStudentScore(CourseTotalScoreOfflineStudentUpdateDTO update) {
        CourseTotalScoreOfflineStudentEntity entity = new CourseTotalScoreOfflineStudentEntity();
        entity.setId(update.getId());
        entity.setScore(update.getScore());
        return this.courseTotalScoreOfflineStudentService.getBaseMapper().updateById(entity) > 0;
    }

    @Override
    public boolean updateBatchStudentScore(List<CourseTotalScoreOfflineStudentUpdateDTO> list){
        CommonErrors.BAD_REQUEST.check(list.size()>0, "参数不能为空");
        List<CourseTotalScoreOfflineStudentEntity> entityList = list.stream().map(item -> {
            CourseTotalScoreOfflineStudentEntity entity = new CourseTotalScoreOfflineStudentEntity();
            entity.setId(item.getId());
            entity.setScore(item.getScore());
            return entity;
        }).collect(Collectors.toList());
        return this.courseTotalScoreOfflineStudentService.updateBatchById(entityList);
    }

    @Override
    public CourseTotalScoreStudentOfflineInfoResultDTO studentOfflineScore(CourseTotalScoreOfflineStudentQueryDTO dto) {

        CourseTotalScoreStudentOfflineInfoResultDTO infoResultDTO = new CourseTotalScoreStudentOfflineInfoResultDTO();
        // 获取线下成绩主信息
        CourseTotalScoreOfflineEntity offlineEntity = this.baseMapper.selectById(dto.getOfflineScoreId());

        infoResultDTO.setFullScore(MathUtils.stripTrailingZeros(offlineEntity.getFullScore(), 1));
        infoResultDTO.setIsShowStudent(offlineEntity.getIsShowStudent() == null ? 1 : offlineEntity.getIsShowStudent());
        infoResultDTO.setIsUserLevelShow(offlineEntity.getIsUseGradeShow());

        if (offlineEntity.getIsShowStudent().equals(0)) {
            return infoResultDTO;
        }

        // 获取计算后的信息
        CourseTotalScoreOfflineResultDTO offline = this.baseMapper.allCourseTotalScoreOffline(dto.getOfflineScoreId());
        infoResultDTO.setAvgScore(MathUtils.stripTrailingZeros(offline.getAvgScore(), 1));

        // 获取等级分制
        CourseTotalScoreOfflineConfigQueryDTO queryDTO = new CourseTotalScoreOfflineConfigQueryDTO();
        queryDTO.setOfflineScoreId(dto.getOfflineScoreId());
        List<CourseTotalScoreOfflineConfigResultDTO> list = courseTotalScoreOfflineConfigService.findCourseTotalScoreOfflineConfig(queryDTO);
        infoResultDTO.setConfigList(list);

        infoResultDTO.setFullGrade(checkTypeGrade(list, infoResultDTO.getFullScore(), infoResultDTO.getFullScore()));
        infoResultDTO.setAvgGrade(checkTypeGrade(list, infoResultDTO.getFullScore(), infoResultDTO.getAvgScore()));

        // 获取学生成绩
        CourseTotalScoreOfflineStudentQueryDTO studentQueryDTO = new CourseTotalScoreOfflineStudentQueryDTO();
        studentQueryDTO.setOfflineScoreId(dto.getOfflineScoreId());
        ClassStudentResultDTO mainStudent = R.as(classStudentClient.findVirtualClassStudentByClassIdAndUserId(offlineEntity.getClassId(), dto.getStudentId()));
        studentQueryDTO.setStudentId(mainStudent.getStudentId());
        CourseTotalScoreOfflineStudentResultDTO studentResultDTOS = courseTotalScoreOfflineStudentService.studentOfflineScore(studentQueryDTO);
        if (studentResultDTOS != null) {
            studentResultDTOS.setScore(MathUtils.stripTrailingZeros(studentResultDTOS.getScore(), 1));
            infoResultDTO.setGrade(checkTypeGrade(list, offlineEntity.getFullScore(), studentResultDTOS.getScore()));
            studentResultDTOS.setIsUseGradeShow(studentResultDTOS.getIsUserLevelShow());
            infoResultDTO.setStudentOffline(studentResultDTOS);
        }
        return infoResultDTO;
    }

    @Override
    public PageInfo<CourseTotalScoreOfflineStudentResultDTO> studentOfflineScorePage(CourseTotalScoreOfflineStudentQueryDTO dto) {
        // 获取学生成绩
        CourseTotalScoreOfflineStudentQueryDTO query = new CourseTotalScoreOfflineStudentQueryDTO();
        query.setStudentId(dto.getStudentId());
        PageInfo<CourseTotalScoreOfflineStudentResultDTO> pages
            = courseTotalScoreOfflineStudentService.studentOfflineScorePage(Pages.page(query), query);
        pages.getRows().forEach(item -> {
            item.setScore(MathUtils.stripTrailingZeros(item.getScore(), 1));
        });
        return pages;
    }

    /**
     * 校验等级值
     */
    private String checkTypeGrade(List<CourseTotalScoreOfflineConfigResultDTO> list, BigDecimal fullScore, BigDecimal studentScore) {
        String grade = "";
        fullScore = fullScore == null ? new BigDecimal(0) : fullScore;
        studentScore = studentScore == null ? new BigDecimal(0) : studentScore;
        for (int i = 0; i < list.size(); i++) {
            CourseTotalScoreOfflineConfigResultDTO item = list.get(i);
            BigDecimal maxScore = fullScore.multiply(new BigDecimal(item.getMax())).divide(new BigDecimal(100), BigDecimal.ROUND_DOWN);
            BigDecimal minScore = fullScore.multiply(new BigDecimal(item.getMin())).divide(new BigDecimal(100), BigDecimal.ROUND_DOWN);
            if (i == 0) {
                if (studentScore.compareTo(minScore) >= 0 && studentScore.compareTo(maxScore) <= 0) {
                    grade = item.getGrade();
                }
            } else {
                if (studentScore.compareTo(minScore) >= 0 && studentScore.compareTo(maxScore) < 0) {
                    grade = item.getGrade();
                }
            }
        }
        return grade;
    }

    @Override
    public void downOfflineExcel(CourseTotalScoreOfflineStudentQueryDTO dto, HttpServletResponse response) {
        // 获取计算后的信息
        CourseTotalScoreOfflineResultDTO offline = this.baseMapper.allCourseTotalScoreOffline(dto.getOfflineScoreId());

        List<CourseTotalScoreOfflineStudentResultDTO> list = this.courseTotalScoreOfflineStudentService.studentOfflineScoreList(dto);
        List<Map<String, Object>> titleList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("title", offline.getScoreTitle() + "线下成绩");
        map.put("unionValue", "studentScore");
        titleList.add(map);

        List<Map<String, Object>> studentList = list.stream().map(v -> {
            Map<String, Object> stuMap = new HashMap<>();
            stuMap.put("avatar", v.getAvatar());
            stuMap.put("nickname", v.getNickname());
            stuMap.put("studentScore", v.getScore());
            return stuMap;
        }).collect(Collectors.toList());

        String description = offline.getScoreTitle() + "线下成绩";
        ClassResultDTO classDto = classClient.findClass(offline.getClassId()).getData();
        CourseResultDTO courseDto = remoteCourseClient.findCourse(classDto.getCourseId()).getData();
        description = courseDto.getCourseName() + " " + classDto.getName() + " " + description;

        XSSFWorkbook workbook = ExcelUtil.createExcel("成绩管理", description, titleList, studentList);
        ExcelUtil.downLoadExcel("成绩管理", response, workbook);

    }


}
